﻿Imports ACompany.OrderProcessing.Model
Imports ACompany.OrderProcessing.Infrastructure
Imports ACompany.OrderProcessing.NhibernateRepository

Public Class OrderService
    Implements IOrderService

    Private _OrderRepository As IOrderRepository
    Private _ProductRepository As IProductRepository
    Private _UnitOfWork As IUnitOfWork

    Public Sub New(ByVal OrderRepository As IOrderRepository, ByVal ProductRepository As IProductRepository, ByVal UnitOfWork As IUnitOfWork)
        Me._ProductRepository = ProductRepository
        Me._ProductRepository.Inject(UnitOfWork)
        Me._OrderRepository = OrderRepository
        Me._OrderRepository.Inject(UnitOfWork)
        Me._UnitOfWork = UnitOfWork
    End Sub

    Public Function GetAllOrdersBy(ByVal Status As Model.OrderStatus) As System.Collections.Generic.List(Of Model.Order) Implements Model.IOrderService.GetAllOrdersBy

        Dim OrderStatusQuery As New Query
        Dim OrdersStatusCriteria As New Criteria("Status", Status, CriteriaOperator.Equals)
        OrderStatusQuery.Criteria.Add(OrdersStatusCriteria)

        Return Me._OrderRepository.FindBy(OrderStatusQuery)

    End Function

    Public Sub Place(ByVal Order As Model.Order) Implements Model.IOrderService.Place

        Me._OrderRepository.Save(Order)
        Me._UnitOfWork.Commit()

    End Sub

    Public Function FindAllOrdersContainingProductBy(ByVal ProductId As Guid) As System.Collections.Generic.List(Of Model.Order) Implements Model.IOrderService.FindAllOrdersContainingProductBy

        Return Me._OrderRepository.FindAllOrdersContainingProductBy(ProductId)

    End Function

    Public Function FindBy(ByVal Id As Guid) As Model.Order Implements Model.IOrderService.FindBy
        Return Me._OrderRepository.FindBy(Id)
    End Function

    Public Sub Process(ByVal Order As Model.Order) Implements Model.IOrderService.Process

        If Order.CanProcess Then

            Order.Process()

            For Each i As Item In Order.Items
                ' Now we need to update the stock
                i.Product.Stock -= i.Qty
                Me._ProductRepository.Save(i.Product)
            Next

            Me._OrderRepository.Save(Order)

            Me._UnitOfWork.Commit()

        Else
            Throw New InvalidOperationException("This order cannot be processed")
        End If

    End Sub

    Public Sub Save(ByVal Order As Model.Order) Implements Model.IOrderService.Save

        If Order.GetBrokenRules.Count = 0 Then

            Me._OrderRepository.Save(Order)
            Me._UnitOfWork.Commit()
        Else

            Dim brokenRules As String = BuildErrorListFrom(Order)

            Throw New InvalidOperationException( _
                String.Format("You cannot save the order because it has broken business rules. {0}", brokenRules))

        End If

    End Sub

    Private Function BuildErrorListFrom(ByVal Order As Order) As String

        Dim brokenRulesList As New Text.StringBuilder

        For Each brokenRule As BrokenRule In Order.GetBrokenRules
            brokenRulesList.Append(brokenRule.Rule)
            brokenRulesList.Append(Environment.NewLine)
        Next

        Return brokenRulesList.ToString

    End Function
End Class
